
#include <string.h>
#include "Debug.h"
/*BSP*/
#include "BSP_Delay.h"
#include "BSP_Sleep.h"
#include "BSP_RS485.h"
/*Driver*/
#include "Light.h"
#include "Buzzer.h"

/*Util*/
#include "MemAlloc.h"
#include "SoftCRC.h"

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

#include "RealTimeClock.h"
#include "Command.h"
#include "DeviceLight.h"
#include "Debug.h"
#include "Env.h"

#include "Token.h"

#include "Controller/controller.h"

void Main_NotifyFromISR(uint8_t* msg);


#define _CMD_DBG	1
#define CMD_DBG(...)	MDBG_PRINT(_CMD_DBG,  __VA_ARGS__)

const char FirmwareVerseion[] = VER_INFO"-"VER_NUM"-"__DATE__"-"__TIME__;


#define UART_STX			0xaa	//
#define UART_ETX			0x55	//

#define WAIT_485_TIME     (50)

#define CMD_IN_CMD_FROM_CONTRALER		151	//
#define CMD_IN_RESULT_FROM_CONTRALER	152	//
#define CMD_OUT_DATA_TO_CONTRALER		200	//
#define CMD_OUT_NULL_DATA_TO_CONTRALER	201	//

#define CMD_SET_OPT		0xCA //202 


#define VS_FP_OR_PW_OR_RF	0 //
#define VS_FP				1 //
#define VS_PIN 				2 //
#define VS_PW 				3 //
#define VS_RF 				4 //
#define VS_FP_OR_PW 		5 //
#define VS_FP_OR_RF			6 //
#define VS_PW_OR_RF 		7 //
#define VS_PIN_AND_FP 		8 //
#define VS_FP_AND_PW 		9 //
#define VS_FP_AND_RF 		10 //
#define VS_FP_AND_PW_AND_RF 11 //
#define VS_PIN_AND_FP_AND_PW 12 //
#define VS_FP_AND_RF_AND_PIN 13 //
#define VS_RF_OR_QR			0x22

enum ECMD{
 CMD_DevAddr = 0,	//0
 CMD_QrPWD,			//1
 CMD_QrAttr,		//2
 CMD_QrDID,			//3
 CMD_WG,			//4
 CMD_TIME,			//5
 CMD_DOOR,			//6
 CMD_LOG,			//7
 CMD_SN,			//8
 CMD_ACTIVATE,		//9
 CMD_QrValidity,	//10
 CMD_DOOR_TIME,		//11
 CMD_TTS,			//12
 CMD_QrTransMode,	//13
 CMD_Mode,			//14
 CMD_IdCard,		//15
 CMD_RdMode,		//16
 CMD_HID_Format,	//17
 CMD_VERSION,		//18
 CMD_WG_Width,		//19
 CMD_WG_Parity,		//20
 CMD_Channel,		//21
 CMD_WG_Reverse,	//22
 CMD_CardOrder,	   //23
 CMD_Text,		//24
 CMD_CardKey,		//25
 CMD_MfCard,		//26
 CMD_CpuCard,		//27
 CMD_ControlReg,	//28
 CMD_APDU,			//29
 CMD_RdSupport,	//30
 
 CMD_UserAdd = 40,	//40
 CMD_UserFind,		//41
 CMD_UserSet,		//42
 CMD_UserRemove,	//43
 CMD_UserRead,		//44
 CMD_UserSeek,		//45
 CMD_UserClear,		//46
 CMD_UserClean,		//47
 CMD_UserSize,		//48
 
 CMD_LogSeek = 50,  //50
 CMD_LogRead,		//51
 CMD_LogFindNext,	//52
 CMD_LogRemove,		//53
 CMD_LogClear,		//54
 CMD_LogClean,		//55
 CMD_LogSize,		//56
 
 CMD_SetBaud = 60,		//
 
 CMD_ConfigReader = 128,
 CMD_ConfigComm = 129,
 CMD_ConfigQr = 130,
 CMD_ConfigDevice = 131,
 CMD_ConfigOther = 132,
};


#pragma pack(1)

typedef struct ReaderConfigTag{
	uint8_t MfKey[6];
	uint8_t MfBlock;
	uint8_t MfOffset;	
	uint8_t CpuKey[16];   //[15]-[30]
	uint16_t CpuDfId;
	uint16_t CpuEfId;     //
	uint8_t Mode;         //[35]
	uint8_t rdSupport[2];	
	uint8_t MifareFirst;  //[38]
	uint8_t InfoOpenDoor; //[39]
	uint8_t CpuKeyId;     //[40]
	
	//CA 
	uint8_t CpuStartPosition; 	  //[51]//Start position of read file that in cpu card.
	uint8_t CpuLength;	  //offset
	uint8_t Customer_Code[4]; 		  //0: without customer code ;	 !0: with customer code.
	uint8_t Customer_CPU_Position;
	uint8_t Customer_M1_Position;

	uint8_t Snr4_StartPos;
	uint8_t Snr4_Len;
	uint8_t Snr8_StartPos;
	uint8_t Snr8_Len;
	  
	uint8_t Options_select;				  //Bit0: mifare card KeyCheck enable;			  Bit1: CPU card KeyCheck enable;	 Bit2:	Customer code select function.
}ReaderConfig_T;

typedef struct CommConfigTag
{
	uint8_t wg;
	uint8_t wgPulseWidth;
	uint8_t wgPulsePuse;
	uint8_t wgReverse;
	uint8_t wgParity;

	uint8_t netMAC[6];
	uint8_t netClientIp[4];
	uint16_t netClientPort;
	uint8_t netServerIp[4];
	uint16_t netServerPort;
	uint8_t netGateWay[4];
	uint8_t netSubMask[4];
	uint8_t netTouchInterval;
}CommConfig_T;

typedef struct QrConfigTag{	
	uint8_t DID;
	uint8_t PwdLen;
	uint8_t Pwd[24];
	uint8_t DMode;
	uint8_t WorkMode;
	uint8_t Validity;
	uint8_t DidOut;
	uint8_t Reverse;
}QrConfig_T;

typedef struct DeviceConfigTag{
	uint8_t address;
	uint8_t doorUnlockTime;
	uint8_t hidFormat;
	uint8_t channelEnable;
	uint8_t devMode;
	uint8_t devSnr[6];
}DeviceConfig_T;

#pragma pack()


static int Command_AddressCheck(uint8_t address){
	if(address == 0xFF){
		return 1;
	}
	if(address == 0x00){
		return 1;
	}
	return envData.devAddr == address;
}


int Command_Validate(unsigned char* buf, unsigned short len){
	unsigned short crc16Result;
	unsigned short crc;
	XferFrame_T* cmd = (XferFrame_T*)buf;

	if(!Command_AddressCheck(cmd->address)){
		return 0;
	}

	crc16Result=crc16(&cmd->address, cmd->length + 4);
	crc = cmd->buffer[cmd->length + 1] << 8 | cmd->buffer[cmd->length];
	if (crc != crc16Result)	{	
		return 0;
	}
	return 1;
}

typedef struct {
	uint8_t count;
	uint8_t value[16];
}KeyWord_T;

extern CSN_T CSN;
volatile uint8_t rebootFlag;
static uint8_t RDY_CardReady;
//	static CSN_T zk_CSN;
static CSN_T* RDY_Csn;
static uint8_t RDY_KeyReady;
static KeyWord_T keyword;

static uint8_t RDY_RxState;
static uint8_t RDY_CmdBuf[260];
static uint8_t RDY_RespBuf[2048 + 64];
static uint16_t RDY_RxOffset;
static uint16_t RDY_RxLength;
static uint8_t RDY_Flag;
static volatile uint16_t connectCount;
static volatile uint8_t commChannel;
static uint8_t sessionChannel;
volatile uint8_t cmdRxLock;
uint8_t cmdLast;
uint8_t cmdRxCount;

static TimerHandle_t commandTimer;

static uint32_t ValidCount;

static uint8_t DK_Command;

typedef struct TokenSlot{
	const Token_T* token;
	int life;
}TokenSlot_T;

static TokenSlot_T tokenTable[TK_Slot_MAX];

void Command_Token_Set(uint8_t slot, const Token_T* token){
	if(slot < TK_Slot_MAX){
		vPortEnterCritical();
		tokenTable[slot].token = token;
		tokenTable[slot].life = 1000;
		vPortExitCritical();
	}
}

const Token_T* Command_Token_Get(uint8_t* slot){
	uint32_t i;

	for(i = 0; i < TK_Slot_MAX; i++){
		if(tokenTable[i].life > 0){
			*slot = i;
			return tokenTable[i].token;
		}
	}
	
	return NULL;
}

int Command_Token_Check(uint8_t slot){
	if(slot < TK_Slot_MAX){
		if(tokenTable[slot].life > 0){
			return 1;
		}
	}
	
	return 0;
}


void Command_Token_Clear(uint8_t slot){
	if(slot < TK_Slot_MAX){
		tokenTable[slot].life = -1;
	}
}

void Command_Timeout(void);

void Command_Token_Fresh(void){
	for(uint32_t i = 0; i < TK_Slot_MAX; i++){
		if(tokenTable[i].life > 0){
			tokenTable[i].life--;
			if(tokenTable[i].life == 0){
				tokenTable[i].life = -1;
				Command_Timeout();
			}
		}
	}
}

uint8_t Command_Token_ToCmdType(const Token_T* token){

	switch(token->type){
	case TK_CARD: return 2;
	case TK_KEY: return 3;
	case TK_QR: return 5;
	}
	
	return 0;
}


void Command_InitReceie(void){
	RDY_RxState = 0;
	commChannel = CH_IDLE;
	cmdRxLock = 0;
}


int Command_Receive(uint8_t channel, uint8_t ch){
	XferFrame_T *cmd = (XferFrame_T*)RDY_CmdBuf;
	
	if(commChannel != channel && cmdRxLock != 0){
		return 0;
	}
	
	cmdRxCount = 3;
	
	switch(RDY_RxState){
	case 0:{
		if(ch == 0xAA){
			RDY_RxState = 1;
			commChannel = channel;
			cmdRxLock = 1;
		}
		else{
			commChannel = CH_IDLE;
		}
	}
	break;

	case 1:{ //Address	
		if(Command_AddressCheck(ch)){
			cmd->address = ch;
			RDY_RxState = 2;
		}
		else{
			RDY_RxState = 100;
			cmdRxCount = 2;
		}
	}
	break;
	case 2: {	//Cmd
		switch(ch){
		case CMD_IN_CMD_FROM_CONTRALER:
		case CMD_IN_RESULT_FROM_CONTRALER:
		case CMD_SET_OPT:
		{
			cmd->code = ch;
			RDY_RxState = 3;
		}
		break;
		case 1:{
			RDY_RxState = 0;
			DK_Command = ch;
			Main_NotifyFromISR(&RDY_Flag);
		}
		break;
		}
	}
	break;
	
	case 3:{ //Length Low
		RDY_RxOffset = 0;
		cmd->length = ch;
		RDY_RxState = 4;
	}
	break;
	
	case 4:{ //Length High
		RDY_RxOffset = 0;
		cmd->length |= ch << 8;
		RDY_RxState = 5;
		if(cmd->length > sizeof(cmd->buffer)){
			//bad frame
			RDY_RxState = 0xFF;
			cmdRxCount = 2;
		}
	}
	break;

	case 5:{ //Data
		if(RDY_RxOffset < sizeof(cmd->buffer)){
			cmd->buffer[RDY_RxOffset++] = ch;
		}
		if(RDY_RxOffset == cmd->length){
			RDY_RxState = 6;
		}
	}
	break;

	case 6:{ //CRC1
		RDY_RxState = 7;
		if(RDY_RxOffset < sizeof(cmd->buffer)){
			cmd->buffer[RDY_RxOffset++] = ch;
		}
	}
	break;

	case 7:{ //CRC2
		if(RDY_RxOffset < sizeof(cmd->buffer)){
			cmd->buffer[RDY_RxOffset++] = ch;
		}
		RDY_RxState = 0;
		cmdRxCount = 0;
		if(sessionChannel == CH_IDLE){
			sessionChannel = commChannel;
			RDY_Flag = 1;
			Main_NotifyFromISR(&RDY_Flag);
		}
		return 1;
	}
	
#if 1
	case 100:{
		//CMD
		cmdRxCount = 2;
		RDY_RxState = 101;
	}
	break;
	
	case 101:{
		//Len1
		cmdRxCount = 2;
		RDY_RxLength = ch;
		RDY_RxState = 102;
	}
	break;
	
	case 102:{
		//Len2
		cmdRxCount = 2;
		RDY_RxLength |= (uint16_t)ch << 8;
		//Add length of CRC
		RDY_RxLength += 2; 
		RDY_RxState = 103;
	}
	break;
	
	case 103:{		
		//Data + CRC
		cmdRxCount = 2;
		--RDY_RxLength;
		if(RDY_RxLength == 0){
			RDY_RxState = 104;
			cmdRxCount = 2;
		}
	}
	break;
	
	case 104:{
		cmdRxCount = 2;
		if(ch == 0x55){
			// Optional ETX
			RDY_RxState = 0;
		}
		else
		if(ch == 0xAA){
			// Or STX
			RDY_RxState = 1;
		}
		else{
			// Others
			RDY_RxState = 0xFF;
			commChannel = CH_IDLE;
		}
	}
	break;
#endif 
	
	default:{
		//Skip unknown data
		if(ch == 0xAA){
			RDY_RxState = 1;
		}
		else{
			commChannel = CH_IDLE;
		}
		cmdRxCount = 2;
	}
	break;
	}

	
	return 0;
}


void Command_InitSend(uint8_t channel){
	if(channel == CH_UART){
		BSP_RS485_SetDir(RS485_DIR_OUT);
		BSP_Sleep_Ms(2);
	}
}

void Command_SendByte(uint8_t channel, uint8_t ch){
	if(channel == CH_HID){
		HID_SendByte(ch);
	}
	else
	if(channel == CH_UART){
		BSP_RS485_RawSendByte(ch);
	}
}

void Command_Flush(uint8_t channel){
	if(channel == CH_HID){
		HID_Flush();
	}
	else
	if(channel == CH_UART){
		BSP_Sleep_Ms(2);
		BSP_RS485_SetDir(RS485_DIR_IN);
	}
}

unsigned short Command_SendByteCrc(uint8_t channel, unsigned char dat, unsigned short crc){
	Command_SendByte(channel, dat);	
	return crc16_byte(crc, dat);
}

void Command_CharSendFrame(uint8_t channel, uint8_t stx, unsigned char address, unsigned char cmd, unsigned char* buf, unsigned short len){
	unsigned short crc = 0;
	unsigned short i;
	
	Command_InitSend(channel);
	Command_SendByte(channel, stx); 	//
	crc = Command_SendByteCrc(channel, address, crc);	//
	crc = Command_SendByteCrc(channel, cmd, crc);			//
	crc = Command_SendByteCrc(channel, (unsigned char)(len & 0xFF), crc);		//
	crc = Command_SendByteCrc(channel, (unsigned char)(len >> 8), crc);		//
	for(i = 0; i < len; i++){
		crc = Command_SendByteCrc(channel, buf[i], crc); 	//
	}
	Command_SendByte(channel, crc & 0xFF);		//CRC L
	Command_SendByte(channel, crc >> 8); 		//CRC H
//		Command_SendByte(UART_ETX); 	//
	Command_Flush(channel);
}


void Command_SendFrame(unsigned char address, unsigned char cmd, unsigned char* buf, unsigned short len){
	Command_CharSendFrame(sessionChannel, UART_STX, address, cmd, buf, len);
}


int Command_CharRawSend(uint8_t channel, uint8_t buf[], uint32_t len){
	uint32_t i;
	
	Command_InitSend(channel);
	for(i = 0; i < len; i++){
		Command_SendByte(channel, buf[i]);
	}
	Command_Flush(channel);
	return 0;
}

static int BuildResponseDataBlock(uint8_t reversal, uint8_t block[], uint8_t type, uint8_t buffer[], uint16_t length){
	int i = 0;
	
	block[i++] = type;//
	block[i++] = length & 0xFF;//
	block[i++] = (length >> 8) & 0xFF;//

	if(reversal){
		int j;
		
		for(j = length; j > 0; j--){
			block[i++] = buffer[j - 1];
		}
	}
	else{
		memcpy(block+i, buffer, length);
		i += length;
	}
	
	return i;
}

uint16_t ResponseDataBlock(uint8_t reader, uint8_t type, const uint8_t data[], uint16_t length, uint16_t crc, uint8_t channel){
	crc = Command_SendByteCrc(channel, reader, crc);	//
	crc = Command_SendByteCrc(channel, type, crc);	//
	crc = Command_SendByteCrc(channel, length & 0xFF, crc);	//
	crc = Command_SendByteCrc(channel, (length >> 8), crc);	//
	
	for(int i = 0; i < length; i++){
		crc = Command_SendByteCrc(channel, data[i], crc);	//
	}
	
	return crc;
}

void Command_SendDataBlock(uint8_t channel, uint8_t stx, unsigned char address, unsigned char cmd, DataBlock_T* block){
	unsigned short crc = 0;
	uint16_t len = block->length + 3 + 1;
	
	Command_InitSend(channel);
	Command_SendByte(channel, stx); 	//
	crc = Command_SendByteCrc(channel, address, crc);	//
	crc = Command_SendByteCrc(channel, cmd, crc);			//
	crc = Command_SendByteCrc(channel, (unsigned char)(len & 0xFF), crc);		//
	crc = Command_SendByteCrc(channel, (unsigned char)(len >> 8), crc); 	//
	crc = ResponseDataBlock(2, block->type, block->data, block->length, crc, channel);
	Command_SendByte(channel, crc & 0xFF);		//CRC L
	Command_SendByte(channel, crc >> 8);		//CRC H
//		Command_SendByte(UART_ETX); 	//
	Command_Flush(channel);
}

#if 0
static int getRespLength(uint8_t keyOrCard){
	int rLen = 0;
	int nlen = RDY_Csn->nlen;
	int ilen = RDY_Csn->ilen;
	int kcount = keyword.count;
	
	if(keyOrCard > 0x0F){
		if(keyOrCard & 0x30){
			if(RDY_CardReady == 2){
				if(keyOrCard & 0x10){
					rLen++;
					rLen += 3 + nlen;
				}
				
				if((keyOrCard & 0x20) && (ilen)){
					rLen++;
					rLen += 3 + ilen;
				}
			}
		}
		
		if(keyOrCard & 0x40){
			if(RDY_KeyReady == 2){
				rLen ++;
				rLen += 3 + kcount;
			}
		}
		return rLen;
	}
	
	
	if (
		( keyOrCard == VS_FP_OR_PW_OR_RF )	||	
		( keyOrCard == VS_RF )				||
		( keyOrCard == VS_FP_OR_RF )		||
		( keyOrCard == VS_PW_OR_RF )		||
		( keyOrCard == VS_FP_AND_RF )		||
		( keyOrCard == VS_FP_AND_RF_AND_PIN )
	){//
		if(RDY_CardReady == 2){
			rLen ++;
			if(!ilen){
				rLen += 3 + nlen;
			}
			else{
				rLen += 3 + ilen;
			}
			return rLen;
		}
	}
	
	if (( keyOrCard == VS_FP_OR_PW_OR_RF )		||
		( keyOrCard == VS_PW )					||
		( keyOrCard == VS_FP_OR_PW )			||
		( keyOrCard == VS_PW_OR_RF )			||
		( keyOrCard == VS_FP_AND_PW ))
	{//KEY

		if(RDY_KeyReady == 2){
			rLen ++;
			rLen += 3 + kcount;
			return rLen;
		}
	}

	if ( keyOrCard == VS_FP_AND_PW_AND_RF )
	{//
		if(RDY_CardReady == 2 && RDY_KeyReady == 2){
			if(nlen == 0 || kcount == 0){
				return 0;
			}
			rLen ++;
			rLen += 3 + nlen;
			rLen ++;
			rLen += 3 + kcount;
			return rLen;
		}
	}

	return rLen;
}
#endif 
static int getRespLength(uint8_t keyOrCard){
	int rLen = 0;
	int nlen = RDY_Csn->nlen;
	int ilen = RDY_Csn->ilen;
	int kcount = keyword.count;
	
	if(keyOrCard > 0x0F){
		if(keyOrCard & 0x30){
			if(RDY_CardReady == 2){
				if(keyOrCard & 0x10){
					rLen++;
					rLen += 3 + nlen;
				}
				
				if((keyOrCard & 0x20) && (ilen)){
					rLen++;
					rLen += 3 + ilen;
				}
			}
		}
		
		if(keyOrCard & 0x40){
			if(RDY_KeyReady == 2){
				rLen ++;
				rLen += 3 + kcount;
			}
		}
		return rLen;
	}
	
	
	if (
		( keyOrCard == VS_FP_OR_PW_OR_RF )	||	
		( keyOrCard == VS_RF )				||
		( keyOrCard == VS_FP_OR_RF )		||
		( keyOrCard == VS_PW_OR_RF )		||
		( keyOrCard == VS_FP_AND_RF )		||
		( keyOrCard == VS_FP_AND_RF_AND_PIN )
	){//
		if(RDY_CardReady == 2){
			rLen ++;
			if(!ilen){
				rLen += 3 + nlen;
			}
			else{
				rLen += 3 + ilen;
			}
			return rLen;
		}
	}
	
	if (( keyOrCard == VS_FP_OR_PW_OR_RF )		||
		( keyOrCard == VS_PW )					||
		( keyOrCard == VS_FP_OR_PW )			||
		( keyOrCard == VS_PW_OR_RF )			||
		( keyOrCard == VS_FP_AND_PW ))
	{//KEY

		if(RDY_KeyReady == 2){
			rLen ++;
			rLen += 3 + kcount;
			return rLen;
		}
	}

	if( keyOrCard == VS_FP_OR_PW_OR_RF ){
		uint8_t slot;
		const Token_T* token = Command_Token_Get(&slot);
		if(token){
			rLen ++;
			rLen += 3 + token->length;
			return rLen;
		}
	}

	if ( keyOrCard == VS_FP_AND_PW_AND_RF )
	{//
		if(RDY_CardReady == 2 && RDY_KeyReady == 2){
			if(nlen == 0 || kcount == 0){
				return 0;
			}
			rLen ++;
			rLen += 3 + nlen;
			rLen ++;
			rLen += 3 + kcount;
			return rLen;
		}
	}

	return rLen;
}

#if 0
static void respComplete(unsigned char keyOrCard){
	if(keyOrCard > 0x0F){
		if(keyOrCard & 0x30){
			if(RDY_CardReady == 2){
				RDY_CardReady = 1;
			}
		}
		
		if(keyOrCard & 0x40){
			if(RDY_KeyReady == 2){
				RDY_KeyReady = 1;
				memset(&keyword, 0, sizeof(keyword));
			}
		}
		return ;
	}
	
	
	if (
		( keyOrCard == VS_FP_OR_PW_OR_RF )	||	
		( keyOrCard == VS_RF )				||
		( keyOrCard == VS_FP_OR_RF )		||
		( keyOrCard == VS_PW_OR_RF )		||
		( keyOrCard == VS_FP_AND_RF )		||
		( keyOrCard == VS_FP_AND_RF_AND_PIN )
	){//
		if(RDY_CardReady == 2){
			RDY_CardReady = 1;
			return ;
		}
	}
	
	if (( keyOrCard == VS_FP_OR_PW_OR_RF )		||
		( keyOrCard == VS_PW )					||
		( keyOrCard == VS_FP_OR_PW )			||
		( keyOrCard == VS_PW_OR_RF )			||
		( keyOrCard == VS_FP_AND_PW ))
	{//KEY 

		if(RDY_KeyReady == 2){
			RDY_KeyReady = 1;
			memset(&keyword, 0, sizeof(keyword));
			return ;
		}
	}

	if ( keyOrCard == VS_FP_AND_PW_AND_RF )
	{//
		if(RDY_CardReady == 2 && RDY_KeyReady == 2){
			RDY_CardReady = 1;
			RDY_KeyReady = 1;
			memset(&keyword, 0, sizeof(keyword));
			return ;
		}
	}
}
#endif 
static void respComplete(unsigned char keyOrCard){
	if(keyOrCard > 0x0F){
		if(keyOrCard & 0x30){
			if(RDY_CardReady == 2){
				RDY_CardReady = 1;
			}
		}
		
		if(keyOrCard & 0x40){
			if(RDY_KeyReady == 2){
				RDY_KeyReady = 1;
				memset(&keyword, 0, sizeof(keyword));
			}
		}
		return ;
	}
	
	
	if (
		( keyOrCard == VS_FP_OR_PW_OR_RF )	||	
		( keyOrCard == VS_RF )				||
		( keyOrCard == VS_FP_OR_RF )		||
		( keyOrCard == VS_PW_OR_RF )		||
		( keyOrCard == VS_FP_AND_RF )		||
		( keyOrCard == VS_FP_AND_RF_AND_PIN )
	){//
		if(RDY_CardReady == 2){
			RDY_CardReady = 1;
			return ;
		}
	}
	
	if (( keyOrCard == VS_FP_OR_PW_OR_RF )		||
		( keyOrCard == VS_PW )					||
		( keyOrCard == VS_FP_OR_PW )			||
		( keyOrCard == VS_PW_OR_RF )			||
		( keyOrCard == VS_FP_AND_PW ))
	{//KEY 

		if(RDY_KeyReady == 2){
			RDY_KeyReady = 1;
			memset(&keyword, 0, sizeof(keyword));
			return ;
		}
	}


	if( keyOrCard == VS_FP_OR_PW_OR_RF ){
		uint8_t slot;
		const Token_T* token = Command_Token_Get(&slot);
		if(token){
			Command_Token_Clear(slot);
		}
	}


	if ( keyOrCard == VS_FP_AND_PW_AND_RF )
	{//
		if(RDY_CardReady == 2 && RDY_KeyReady == 2){
			RDY_CardReady = 1;
			RDY_KeyReady = 1;
			memset(&keyword, 0, sizeof(keyword));
			return ;
		}
	}
}

int uploadCardOrKeyVal(unsigned char keyOrCard)
{	
	uint16_t rLen = 0;
	uint8_t ret = CMD_OUT_NULL_DATA_TO_CONTRALER;
	keyOrCard = 0;
	cmdLast = keyOrCard;
	BSP_Sleep_Ms(WAIT_485_TIME); //
	unsigned short crc = 0;
	uint8_t channel = sessionChannel;
	rLen = getRespLength(keyOrCard);
	if(rLen){
		ret = CMD_OUT_DATA_TO_CONTRALER;
	}
	else{
		rLen = 1;
	}
	Command_InitSend(channel);
	Command_SendByte(channel, UART_STX); 	//
	crc = Command_SendByteCrc(channel, envData.devAddr, crc);	//
	crc = Command_SendByteCrc(channel, ret, crc);			//
	crc = Command_SendByteCrc(channel, (unsigned char)(rLen & 0xFF), crc);		//
	crc = Command_SendByteCrc(channel, (unsigned char)(rLen >> 8), crc); 	//

	if(keyOrCard > 0x0F){
		if(keyOrCard & 0x30){
			if(RDY_CardReady == 2){
				if(keyOrCard & 0x10){
					crc = ResponseDataBlock(2, 2, RDY_Csn->num, RDY_Csn->nlen, crc, channel);
				}
				
				if((keyOrCard & 0x20) && (RDY_Csn->ilen)){
					crc = ResponseDataBlock(2, 0x40, RDY_Csn->ibuf, RDY_Csn->ilen, crc, channel);
				}
				ret = CMD_OUT_DATA_TO_CONTRALER;
			}
			else{			
				RDY_CardReady = 1;
			}
		}
		
		if(keyOrCard & 0x40){
			if(RDY_KeyReady == 2){
				crc = ResponseDataBlock(2, 3, keyword.value, keyword.count, crc, channel);
				ret = CMD_OUT_DATA_TO_CONTRALER;
				goto OUT;
			}
			else{
				RDY_KeyReady = 1;
			}
		}
		goto OUT;
	}
	
	
	if (
		( keyOrCard == VS_FP_OR_PW_OR_RF )	||	
		( keyOrCard == VS_RF )				||
		( keyOrCard == VS_FP_OR_RF )		||
		( keyOrCard == VS_PW_OR_RF )		||
		( keyOrCard == VS_FP_AND_RF )		||
		( keyOrCard == VS_FP_AND_RF_AND_PIN )
	){//
		if(RDY_CardReady == 2){
			if(!RDY_Csn->ilen){
				crc = ResponseDataBlock(2, 2, RDY_Csn->num, RDY_Csn->nlen, crc, channel);
			}
			else{
				crc = ResponseDataBlock(2, 0x40, RDY_Csn->ibuf, RDY_Csn->ilen, crc, channel);
			}
			goto OUT;
		}
		else{			
			RDY_CardReady = 1;
		}
	}
	
	if (( keyOrCard == VS_FP_OR_PW_OR_RF )		||
		( keyOrCard == VS_PW )					||
		( keyOrCard == VS_FP_OR_PW )			||
		( keyOrCard == VS_PW_OR_RF )			||
		( keyOrCard == VS_FP_AND_PW ))
	{//

		if(RDY_KeyReady == 2){
			crc = ResponseDataBlock(2, 3, keyword.value, keyword.count, crc, channel);
			goto OUT;
		}
		else{
			RDY_KeyReady = 1;
		}
	}

	if( keyOrCard == VS_FP_OR_PW_OR_RF ){
		uint8_t slot;
		const Token_T* token = Command_Token_Get(&slot);
		if(token){
			uint8_t type = Command_Token_ToCmdType(token);
			crc = ResponseDataBlock(2, type, token->data, token->length, crc, channel);
			goto OUT;
		}
	}
	
	if ( keyOrCard == VS_FP_AND_PW_AND_RF )
	{//
		if(RDY_CardReady == 2 && RDY_KeyReady == 2){
			crc = ResponseDataBlock(2, 2, RDY_Csn->num, RDY_Csn->nlen, crc, channel);
			crc = ResponseDataBlock(2, 3, keyword.value, keyword.count, crc, channel);
			goto OUT;
		}
		else{			
			RDY_CardReady = 1;
			RDY_KeyReady = 1;
		}
	}
	
OUT:
	
	if(ret == CMD_OUT_NULL_DATA_TO_CONTRALER){
		crc = Command_SendByteCrc(channel, 0, crc);
	}
	else{
	}
	Command_SendByte(channel, crc & 0xFF);		//CRC L
	Command_SendByte(channel, crc >> 8);		//CRC H
	Command_Flush(channel);
	return ret;
}


static void resultOK(void){	
	DeviceLight_Flash(1, Color_Green, 300);
	Buzzer_AsyncBeepMult(1, 300, 300);
}

static void resultFail(unsigned char c, unsigned char d){
	DeviceLight_Flash(c, Color_Red, d);
	Buzzer_AsyncBeepMult(c, d, d);
}



void Command_StopValidTimer(void){
	ValidCount = 0;
}

void resultProcess(unsigned char cmd)
{	
	switch(cmd){
	case 0x00:	{
		resultOK();
	}
	break;

	case 0xFE:{
		resultFail(2, 100);
	}
	break;
	case 0xFF:{
		resultFail(3, 80);
	}
	break;
	}
	
	respComplete(cmdLast);
	Command_StopValidTimer();
}


#if 0
static unsigned char* optAlloc(unsigned char cmd){
	unsigned int length;
	if(CMD_IdCard == cmd 
		|| CMD_UserRead == cmd 
		|| CMD_LogRead == cmd){
		length = 1024 + 512 + 1024;
	}
	else{
		length = 128;
	}
	return (unsigned char*)mem_alloc(length);
}
#endif 


#define ENV_UPDATE(env, val, status)	do{env = val; status = 0; Env_Update();}while(0)
static inline void Debug_Buf(uint8_t buf[], uint32_t len){
	uint32_t i;
	for (i = 0; i < len; ++i){
		DBG_PRINT("%02X", buf[i]);
	}
}

static inline void Debug_ReaderConfig(ReaderConfig_T* rd){

    DBG_PRINT("rd->MfKey=");Debug_Buf(rd->MfKey, sizeof(rd->MfKey));DBG_PRINT("\n");
	DBG_PRINT("rd->MfBlock=%02X\n", rd->MfBlock);	
	DBG_PRINT("rd->MfOffset=%02X\n", rd->MfOffset);
	DBG_PRINT("rd->CpuKey=");Debug_Buf(rd->CpuKey, sizeof(rd->CpuKey));DBG_PRINT("\n");
	DBG_PRINT("rd->CpuDfId=%04X\n", rd->CpuDfId);	
	DBG_PRINT("rd->CpuEfId=%04X\n", rd->CpuEfId);
	DBG_PRINT("rd->Mode=%02X\n", rd->Mode);
	DBG_PRINT("rd->Support=%02X,%02X\n", rd->rdSupport[0], rd->rdSupport[1]);	
	DBG_PRINT("rd->MifareFirst=%02X\n", rd->MifareFirst);
	DBG_PRINT("rd->InfoOpenDoor=%02X\n", rd->InfoOpenDoor);
	DBG_PRINT("rd->CpuKeyId=%02X\n", rd->CpuKeyId);
	
	
	DBG_PRINT("rd->CpuStartPosition=%02X\n", rd->CpuStartPosition);
	DBG_PRINT("rd->CpuLength=%02X\n", rd->CpuLength);
	DBG_PRINT("rd->Customer_CPU_Position=%02X\n", rd->Customer_CPU_Position);
	DBG_PRINT("rd->Customer_M1_Position=%02X\n", rd->Customer_M1_Position);
	DBG_PRINT("rd->Customer_Code=%02X\n"); Debug_Buf(rd->Customer_Code, sizeof(rd->Customer_Code));DBG_PRINT("\n");

	DBG_PRINT("rd->Snr4_StartPos=%02X\n", rd->Snr4_StartPos);
	DBG_PRINT("rd->Snr4_Len=%02X\n", rd->Snr4_Len);
	DBG_PRINT("rd->Snr8_StartPos=%02X\n", rd->Snr8_StartPos);
	DBG_PRINT("rd->Snr8_Len=%02X\n", rd->Snr8_Len);
	DBG_PRINT("rd->Options_select=%02X\n", rd->Options_select);
	DBG_PRINT("\n");
}

#define DBG_ReaderConfig(rd)	Debug_ReaderConfig(rd)

static uint8_t ReaderConfig_Set(uint8_t* buf){
	ReaderConfig_T* rd = (ReaderConfig_T*)buf;

	envData.rdMode = rd->Mode;//[35]
	envData.rdCpuDfId = rd->CpuDfId;
	envData.rdCpuEfId = rd->CpuEfId;
	envData.rdMfBlock = rd->MfBlock;
	envData.rdMfOffset = rd->MfOffset;
	envData.rdMifareFirst = rd->MifareFirst;
	envData.rdInfoOpenDoor = rd->InfoOpenDoor;
	envData.rdCpuKeyId = rd->CpuKeyId;
	
	memcpy(envData.rdCpuKey, rd->CpuKey, sizeof(rd->CpuKey));//16 BYTE
	memcpy(envData.rdMfKey, rd->MfKey, sizeof(rd->MfKey));//6 BYTE
	memcpy(envData.rdSupport, rd->rdSupport, sizeof(rd->rdSupport));

    envData.ContentStartPosition=rd->CpuStartPosition;
	envData.ContentLength=rd->CpuLength;
	envData.Customer_CPU_Position=rd->Customer_CPU_Position;
	envData.Customer_M1_Position=rd->Customer_M1_Position;
	memcpy(envData.Customer_Code, rd->Customer_Code, sizeof(rd->Customer_Code));//4 BYTE
    
	

    envData.Snr4_StartPos=rd->Snr4_StartPos;
	envData.Snr4_Len=rd->Snr4_Len;
	envData.Snr8_StartPos=rd->Snr8_StartPos;
	envData.Snr8_Len=rd->Snr8_Len;
	envData.Options_select=rd->Options_select;

	
	
	CMD_DBG("RD Set\n");
	DBG_ReaderConfig(rd);
	Env_Update();
	return 0;
}

static uint8_t ReaderConfig_Get(uint8_t* buf){
	ReaderConfig_T* rd = (ReaderConfig_T*)buf;

	rd->Mode = envData.rdMode;
	rd->CpuDfId = envData.rdCpuDfId;
	rd->CpuEfId = envData.rdCpuEfId;
	rd->MfBlock = envData.rdMfBlock;
	rd->MfOffset = envData.rdMfOffset;
	rd->MifareFirst = envData.rdMifareFirst;
	rd->InfoOpenDoor = envData.rdInfoOpenDoor;
	rd->CpuKeyId = envData.rdCpuKeyId;
	
	memcpy(rd->CpuKey, envData.rdCpuKey, sizeof(rd->CpuKey));
	memcpy(rd->MfKey, envData.rdMfKey, sizeof(rd->MfKey));	
	memcpy(rd->rdSupport, envData.rdSupport, sizeof(rd->rdSupport));

	rd->CpuStartPosition=envData.ContentStartPosition;
	rd->CpuLength=envData.ContentLength;
	rd->Customer_CPU_Position=envData.Customer_CPU_Position;
	rd->Customer_M1_Position=envData.Customer_M1_Position;
	memcpy(rd->Customer_Code,envData.Customer_Code,sizeof(envData.Customer_Code));//4 BYTE

	rd->Snr4_StartPos=envData.Snr4_StartPos;
	rd->Snr4_Len=envData.Snr4_Len;
	rd->Snr8_StartPos=envData.Snr8_StartPos;
	rd->Snr8_Len=envData.Snr8_Len;
	rd->Options_select=envData.Options_select;
	CMD_DBG("RD Get\n");
	DBG_ReaderConfig(rd);
	return sizeof(*rd);
}


static inline void Debug_QrConfig(QrConfig_T* qr){
	DBG_PRINT("qr->DID=%02X\n",  qr->DID);
	DBG_PRINT("qr->DMode=%02X\n",  qr->DMode);
	DBG_PRINT("qr->DidOut=%02X\n",  qr->DidOut);
	DBG_PRINT("qr->Validity=%02X\n",  qr->Validity);
	DBG_PRINT("qr->WorkMode=%02X\n",  qr->WorkMode);
	DBG_PRINT("qr->PwdLen=%02X\n",  qr->PwdLen);
	DBG_PRINT("qr->Pwd=");Debug_Buf(qr->Pwd, qr->PwdLen);DBG_PRINT("\n");
	DBG_PRINT("\n");
}

#define DBG_QrConfig(qr)	Debug_QrConfig(qr)

static uint8_t QrConfig_Set(uint8_t* buf){
	QrConfig_T* qr = (QrConfig_T*)buf;
	
	envData.qrDID = qr->DID;
	envData.qrDMode = qr->DMode;
	envData.qrValidity = qr->Validity;
	envData.qrWorkMode = qr->WorkMode;
	envData.qrPwdLen = qr->PwdLen;
	envData.qrDidOut = qr->DidOut;
	memcpy(envData.qrPwd, qr->Pwd, qr->PwdLen);
	envData.qrReverse = qr->Reverse;
	CMD_DBG("Qr Set\n");
	DBG_QrConfig(qr);
	Env_Update();
	return 0;
}

static uint8_t QrConfig_Get(uint8_t* buf){
	QrConfig_T* qr = (QrConfig_T*)buf;
	
	qr->DID = envData.qrDID;
	qr->DidOut = envData.qrDidOut;
	qr->DMode = envData.qrDMode;
	qr->Validity = envData.qrValidity;
	qr->WorkMode = envData.qrWorkMode;
	qr->PwdLen = envData.qrPwdLen;
	memcpy(qr->Pwd, envData.qrPwd, qr->PwdLen);
	qr->Reverse = envData.qrReverse;
	CMD_DBG("Qr Get\n");
	DBG_QrConfig(qr);
	return sizeof(*qr);
}

static inline void Debug_DeviceConfig(DeviceConfig_T* dev){
	DBG_PRINT("dev->address=%02X\n",  dev->address);
	DBG_PRINT("dev->doorUnlockTime=%02X\n",  dev->doorUnlockTime);
	DBG_PRINT("dev->hidFormat=%02X\n",  dev->hidFormat);
	DBG_PRINT("dev->channelEnable=%02X\n",  dev->channelEnable);
	DBG_PRINT("dev->devMode=%02X\n",  dev->devMode);
	DBG_PRINT("\n");
}

#define DBG_DeviceConfig(qr)	Debug_DeviceConfig(qr)

static uint8_t DeviceConfig_Set(uint8_t* buf){
	DeviceConfig_T* dev = (DeviceConfig_T*)buf;

	envData.devAddr = dev->address;
	envData.devMode = dev->devMode;
	envData.doorUnlockTime = dev->doorUnlockTime;	
	envData.hidFormat = dev->hidFormat;
	envData.channelEnable = dev->channelEnable;
	memcpy(envData.devSnr, dev->devSnr, sizeof(dev->devSnr));
	CMD_DBG("Device Set\n");
	DBG_DeviceConfig(dev);
//		RealTimeClock_SetBCD((TimeBCD *) dev->rtc);
	Env_Update();
	return 0;
}

static uint8_t DeviceConfig_Get(uint8_t* buf){
	DeviceConfig_T* dev = (DeviceConfig_T*)buf;

	dev->address = envData.devAddr;
	dev->doorUnlockTime = envData.doorUnlockTime;
	dev->hidFormat = envData.hidFormat;
	dev->channelEnable = envData.channelEnable;
	dev->devMode = envData.devMode;
	memcpy(dev->devSnr, envData.devSnr, sizeof(dev->devSnr));
	CMD_DBG("Device Get\n");
	DBG_DeviceConfig(dev);
//		RealTimeClock_GetBCD((TimeBCD *) dev->rtc);
	return sizeof (*dev);
}

static inline void Debug_CommConfig(CommConfig_T* comm){
	DBG_PRINT("comm->wg=%02X\n",  comm->wg);
	DBG_PRINT("comm->wgParityFlag=%02X\n",  comm->wgParity);
	DBG_PRINT("comm->wgReverse=%02X\n",  comm->wgReverse);
	DBG_PRINT("comm->wgPulseWidth=%02X\n",  comm->wgPulseWidth);
	DBG_PRINT("comm->wgPulsePuse=%02X\n",  comm->wgPulsePuse);

	DBG_PRINT("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",comm->netMAC[0],comm->netMAC[1],comm->netMAC[2],
			  comm->netMAC[3],comm->netMAC[4],comm->netMAC[5]);
	DBG_PRINT("CIP: %d.%d.%d.%d\r\n", comm->netClientIp[0],comm->netClientIp[1],comm->netClientIp[2],comm->netClientIp[3]);
	DBG_PRINT("CPORT: %d\r\n", comm->netClientPort);
	DBG_PRINT("SIP: %d.%d.%d.%d\r\n", comm->netServerIp[0],comm->netServerIp[1],comm->netServerIp[2],comm->netServerIp[3]);
	DBG_PRINT("SPORT: %d\r\n", comm->netServerPort);
	DBG_PRINT("GW: %d.%d.%d.%d\r\n", comm->netGateWay[0],comm->netGateWay[1],comm->netGateWay[2],comm->netGateWay[3]);
	DBG_PRINT("SUB: %d.%d.%d.%d\r\n", comm->netSubMask[0],comm->netSubMask[1],comm->netSubMask[2],comm->netSubMask[3]);
	DBG_PRINT("Tounch:%d\n", comm->netTouchInterval);
	DBG_PRINT("\n");
}

#define DBG_CommConfig(qr)	Debug_CommConfig(qr)

static uint8_t CommConfig_Set(uint8_t* buf){
	CommConfig_T* comm = (CommConfig_T*)buf;
	
	envData.wg = comm->wg > 66 ? 66 : comm->wg;
	envData.wgParityFlag = comm->wgParity;
	envData.wgReverse = comm->wgReverse;
	envData.wgPulseWidth[0] = comm->wgPulseWidth;
	envData.wgPulseWidth[1] = comm->wgPulsePuse;

	memcpy(envData.netMAC, comm->netMAC, sizeof(comm->netMAC));
	memcpy(envData.netClientIp, comm->netClientIp, sizeof(comm->netClientIp));
	memcpy(envData.netServerIp, comm->netServerIp, sizeof(comm->netServerIp));
	memcpy(envData.netGateWay, comm->netGateWay, sizeof(comm->netGateWay));
	memcpy(envData.netSubMask, comm->netSubMask, sizeof(comm->netSubMask));

	envData.netClientPort = comm->netClientPort;
	envData.netServerPort = comm->netServerPort;
	envData.netHeartbeat = comm->netTouchInterval;
	CMD_DBG("Comm Set\n");
	DBG_CommConfig(comm);
	Env_Update();
	return 0;
}

static uint8_t CommConfig_Get(uint8_t* buf){
	CommConfig_T* comm = (CommConfig_T*)buf;
	
	comm->wg = envData.wg;
	comm->wgParity = envData.wgParityFlag;
	comm->wgReverse = envData.wgReverse;
	comm->wgPulseWidth = envData.wgPulseWidth[0];
	comm->wgPulsePuse = envData.wgPulseWidth[1];

	memcpy(comm->netMAC, envData.netMAC, sizeof(comm->netMAC));
	memcpy(comm->netClientIp, envData.netClientIp, sizeof(comm->netClientIp));
	memcpy(comm->netServerIp, envData.netServerIp, sizeof(comm->netServerIp));
	memcpy(comm->netGateWay, envData.netGateWay, sizeof(comm->netGateWay));
	memcpy(comm->netSubMask, envData.netSubMask, sizeof(comm->netSubMask));

	comm->netClientPort = envData.netClientPort;
	comm->netServerPort = envData.netServerPort;
	comm->netTouchInterval = envData.netHeartbeat;

	CMD_DBG("Comm Get\n");
	DBG_CommConfig(comm);
	return sizeof(*comm);
}

static int Command_SetRTC(uint8_t* buf){
	RealTimeClock_SetBCD((TimeBCD*)buf);
	return 0;
}

static int Command_GetRTC(uint8_t* buf){
	RealTimeClock_GetBCD((TimeBCD*)buf);
	return 0;
}

int optProcess(unsigned char* buf, unsigned char len, unsigned char isResp){
	unsigned short rLen = 0;
	unsigned char* rBuf;
	unsigned char ret = CMD_OUT_NULL_DATA_TO_CONTRALER;
	unsigned char status = 1;
	unsigned char cmd = buf[0];
	unsigned char op = buf[1];
	unsigned char* data = &buf[2];
	
	rBuf = RDY_RespBuf;
	
	switch(cmd){

	case CMD_ConfigReader:{
		if(op){
			status = ReaderConfig_Set(&buf[2]);			
		}
		else{
			rLen = ReaderConfig_Get(rBuf);
		}
	}
	break;

	case CMD_ConfigQr:{
		if(op){
			status = QrConfig_Set(&buf[2]);
		}
		else{
			rLen = QrConfig_Get(rBuf);
		}
	}
	break;

	case CMD_ConfigDevice:{
		if(op){
			status = DeviceConfig_Set(&buf[2]);
		}
		else{
			rLen = DeviceConfig_Get(rBuf);
		}
	}
	break;

	case CMD_ConfigComm:{
		if(op){
			status = CommConfig_Set(&buf[2]);
		}
		else{
			rLen = CommConfig_Get(rBuf);
		}
	}
	break;	

	case CMD_SetBaud:{
		if(op){
			uint32_t baud;
			memcpy(&baud, data, 4);
			if(baud == 9600 || baud == 115200){
				envData.baudrate = baud;
				Env_Update();
	 			status = 0;
			}
		}
		else{
			memcpy(rBuf, &envData.baudrate, 4);
			rLen = 4;
		}
	}
	break;
	case CMD_TIME:{
		if(buf[1]){
			status = Command_SetRTC(&buf[2]);
		}
		else{	//
			Command_GetRTC(rBuf);
			rLen = 7;
		}
	}
	break;
	
	case CMD_UserAdd :{
		user_info_t *user = (user_info_t*)data;
		if(controller_update_user(user) == 0){
			status = 0;
		}
	}
	break;
	case CMD_UserFind :{

	}
	break;
	case CMD_UserRemove :{

	}
	break;
	case CMD_IdCard:{
		if(op == 3){
			break;
		}
		
		if(op == 2){
			rLen = RDY_Csn->nlen;
			if(rLen > 0){
				memcpy(rBuf, RDY_Csn->num, rLen);
				RDY_Csn->nlen = 0;
			}
			break;
		}
		ValidCount = 0;
		if(RDY_Csn->ilen > sizeof(RDY_Csn->ibuf)){
			RDY_Csn->ilen = 0;
			rLen = 0;
			break;
		}
		rLen = RDY_Csn->ilen;
		if(rLen > 0){
			memcpy(rBuf, RDY_Csn->ibuf, rLen);
			RDY_Csn->ilen = 0;
		}
	}
	break;

	case CMD_VERSION:{
		if(!op){
			rLen = strlen(FirmwareVerseion);
			memcpy(rBuf, FirmwareVerseion, rLen);
		}
	}
	break;
	case CMD_DOOR_TIME:{
		if(op){
			ENV_UPDATE(envData.doorUnlockTime, buf[2], status);
		}
		else{
			rBuf[rLen++] = envData.doorUnlockTime;
		}
	}
	break;

	case 0xF0: {
		rebootFlag = 1;
	}
	break;

	case 0xFE: {
		const uint8_t* SN = (const uint8_t*) (0x08003800 - 8);
		memcpy(rBuf, SN, 8);
		rLen = 8;
	}
	break;
	
	case 0xFF:{
		if(op){
			Env_Reset();
			Env_Update();
			status = 0;
		}
	}
	break;
	
	default :
		return -2;
	}

	if(rLen > 0){
		ret = CMD_OUT_DATA_TO_CONTRALER;
	}
	
	if(isResp){
		BSP_Sleep_Ms(WAIT_485_TIME);
		if(ret == CMD_OUT_NULL_DATA_TO_CONTRALER){
			Command_SendFrame(envData.devAddr, ret, &status, sizeof(status));
		}
		else{
			Command_SendFrame(envData.devAddr, ret, rBuf, rLen);
		}
	}

	if(ret == CMD_OUT_DATA_TO_CONTRALER){
		return 1;
	}
	if(status){
		return -1;
	}
	return 1;
}


int Command_DoProcess(unsigned char* buf, unsigned short len){
	
	if(!Command_Validate(buf, len)){
		return -1;
	}
	
	switch (buf[2])
	{
		case CMD_IN_CMD_FROM_CONTRALER ://0x97
			return uploadCardOrKeyVal(buf[5]);
			break;
		case CMD_IN_RESULT_FROM_CONTRALER ://0x98
			resultProcess(buf[5]);
			break;
		case CMD_SET_OPT:		//0xCA
			Env_Lock();
			optProcess(&buf[5], buf[3], 1);
			Env_Unlock();
			break;
		default:
			return -2;
	}
	return 0;

}


void DKCommand_ReportCSN(CSN_T* csn){
	const uint8_t * data;
	uint8_t len;
	
	if(csn->ilen){
		len = csn->ilen;
		data = csn->ibuf;
	}
	else{
		len = csn->nlen;
		data = csn->num;
	}
	
	Command_SendByte(CH_UART, UART_STX); 	//
	Command_SendByte(CH_UART, 1 + 1 + len); 	//
	Command_SendByte(CH_UART, 1); 	//
	Command_SendByte(CH_UART, csn->type);
	
	for(uint32_t i = 0; i < len; i++){
		Command_SendByte(CH_UART, data[i]);
	}
}

void DKCommand_ReportNAK(void){
	Command_SendByte(CH_UART, UART_STX); 	//
	Command_SendByte(CH_UART, 1); 	//
	Command_SendByte(CH_UART, 0xE1);
}

void DKCommand_Response(uint8_t status, uint8_t *data, uint8_t length){
	Command_SendByte(CH_UART, UART_STX); 	//
	Command_SendByte(CH_UART, length + 1); 	//
	Command_SendByte(CH_UART, status);
	for(uint32_t i = 0; i < length; i++){
		Command_SendByte(CH_UART, data[i]);
	}
}


static void DKCommand_Proc(void){
	if(RDY_CardReady == 2){
		if(RDY_Csn->ilen){
			DKCommand_Response(DK_Command, RDY_Csn->ibuf, RDY_Csn->ilen);
		}
		else{
			DKCommand_Response(DK_Command, RDY_Csn->num, RDY_Csn->nlen);
		}
	}
	else{
		DKCommand_Response(0xE1, NULL, 0);
	}
	RDY_CardReady = 1;
}


void Command_Process(void){	
	if(RDY_Flag){
		RDY_Flag = 0;
		connectCount = 800;
		int ret = Command_DoProcess(RDY_CmdBuf, RDY_RxOffset);
		sessionChannel = CH_IDLE;
	}
#if 0
	else{
		if(DK_Command){
			ValidCount = 0;
			connectCount = 200;
			DKCommand_Proc();
			DK_Command = 0;
		}
	}
#endif 
}


void Command_Rs485Out(CSN_T *csn){
	if(RDY_CardReady){
//			zk_CSN = csn;
		RDY_Csn = csn;
		RDY_CardReady = 2;
		ValidCount = 1000;
	}
}


void Command_SyncSend(CSN_T *csn){

#if 1
	DataBlock_T block;
	if(csn->ilen){
		block.data = csn->ibuf;
		block.length = csn->ilen;
		block.type = 0x40;
	}
	else{
		block.data = csn->num;
		block.length = csn->nlen;
		block.type = 2;
	}
	Command_SendDataBlock(CH_UART, UART_STX, envData.devAddr, CMD_OUT_DATA_TO_CONTRALER, &block);
#endif 
}

void Command_Rs485OutKey(uint8_t kval){
	if(RDY_KeyReady){
		ValidCount = 1000;
		uint8_t kcode = ValueToHexCode(kval);
		if(kcode == 'B')
		{
			if ( keyword.count == 0 )
			{
				RDY_KeyReady = 1;
				ValidCount = 0;
			}
			else
			{
				RDY_KeyReady = 2;
			}
		}
		else if(kcode == 'A')
		{
			RDY_KeyReady = 1;
			ValidCount = 0;
			memset(&keyword, 0, sizeof(keyword));
		}
		else
		{
			if (keyword.count < sizeof(keyword.value)){
				keyword.value[keyword.count++] = kcode;
			}
			else{
				RDY_KeyReady = 1;
				keyword.count = 0;
			}
		}
	}
}

void Command_Timeout(void){
	unsigned char i;
	
	for(i = 0; i < 3; i++){
		Buzzer_On();
		BSP_Sleep_Ms(100);
		Buzzer_Off();
		BSP_Sleep_Ms(100);
	}
}


static void cmdTimerCallback(void* p){

	if(cmdRxCount){
		if(--cmdRxCount == 0){
			Command_InitReceie();
		}
	}
	
	if(ValidCount){
		if(--ValidCount == 0){
			if(RDY_CardReady == 2){
				RDY_CardReady = 1;
			}
			if(RDY_KeyReady == 2){
				RDY_KeyReady = 1;
				memset(&keyword, 0, sizeof(keyword));
			}
			Command_Timeout();
		}
	}
	if(connectCount){
		--connectCount;
		if(connectCount == 0){
			if(RDY_CardReady == 2){
				RDY_CardReady = 1;
			}
		}
	}
	Command_Token_Fresh();
}

#if 0
static StreamBufferHandle_t cmdStream;

static void Command_Task(void *param){
	int rlen;
	xStreamBufferReset(cmdStream);
	
	while(1){
		rlen = xStreamBufferReceive(cmdStream, buf, sizeof(buf), 5)
	}
}
#endif 


void Command_Init(void){
	Command_InitReceie();
#if 0
	cmdStream = xStreamBufferCreate(256, 3);
	xTaskCreate(Command_Task, (const char *)"Command", 256, NULL, 3,
								  (xTaskHandle *)NULL);
#endif 
	commandTimer =
		xTimerCreate(/* Just a text name, not used by the RTOS kernel. */
					 "commandTimer",
					 /* The timer period in ticks, must be greater than 0. */
					 pdMS_TO_TICKS(5),
					 /* The timers will auto-reload themselves when they
					 expire. */
					 pdTRUE,
					 /* The ID is used to store a count of the number of
					 times the timer has expired, which is initialized to 0. */
					 (void *)0,
					 /* Each timer calls the same callback when it expires. */
					 cmdTimerCallback);
	xTimerStart(commandTimer, 1000);
}


int Command_Idle(uint8_t flag){
	if((flag & 0x01) && (connectCount == 0)){
		return 1;
	}
	
	if((flag & 0x02) && RDY_CardReady < 2){
		return 1;
	}

	if((flag & 0x04) && RDY_KeyReady < 2){
		return 1;
	}
	
	return 0;
}


